#pragma once

#include "Log.h"
#include "Protocol.h"
#include <string>
#include <iostream>
#include <cstdlib>
#include <functional>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

namespace server {
    using namespace std;

    enum {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR
    };

    // WebCalculator通信服务端
    class CalculatorServer {
    private:
        using func_t = function<void(const Request&, Response&)>;

    private:
        int _listen_sockfd; // 用于监听的套接字，是用来获取链接的，而不是用来通信的
        uint16_t _port;
        func_t _service;

    public:
        CalculatorServer(const func_t& service, const uint16_t& port = 18989)
            : _listen_sockfd(-1)
            , _port(port)
            , _service(service)
        {}

        ~CalculatorServer() {
            close(_listen_sockfd); // 关闭监听套接字，避免套接字泄漏(内存泄漏)
        }

    public:
        void initServer() {
            // 创建监听套接字
            _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_listen_sockfd < 0) { // 创建套接字失败
                logMessage(FATAL, "create listen_socket err!");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL, "create listen_socket success: %d", _listen_sockfd);

            // 服务端绑定服务器的特定端口
            struct sockaddr_in host;
            bzero(&host, sizeof(host));
            host.sin_family = AF_INET;
            host.sin_port = htons(_port);
            host.sin_addr.s_addr = htonl(INADDR_ANY); // 不绑定特定ip
            if (bind(_listen_sockfd, (struct sockaddr*)&host, sizeof(host)) < 0) {
                logMessage(FATAL, "bind listen_socket err!");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "bind listen_socket success!");

            // 设置监听状态，等待客户端连接
            if (listen(_listen_sockfd, 5/*之后再来解释这个参数*/) < 0) {
                logMessage(FATAL, "listen state set fail!");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL, "listen state set success!");
        }

        void start() {
            signal(SIGCHLD, SIG_IGN);

            for (;;) {
                // 接收客户端的链接请求，并创建一个与之通信的套接字
                struct sockaddr_in client;
                socklen_t len = sizeof(client);
                int sockfd = accept(_listen_sockfd, (struct sockaddr*)&client, &len);
                if (sockfd < 0 ) {
                    // 如果与客户端建立连接失败了，不需要退出
                    // 连接建立失败是常事，如果但凡有一个连接失败服务端就退出的话
                    // 那么其他客户也都别用了
                    // 继续接收下一个连接请求就行
                    logMessage(ERROR, "accept link request err!");
                    continue;
                }
                logMessage(NORMAL, "accept a new link request success, the new sockfd is: %d", sockfd);
                
                //task 与客户端之间进行信息交流(业务处理)

                //* 多进程(通过忽略信号SIGCHLD，来实现让OS帮忙回收子进程资源，linux特供)
                pid_t pid = fork();
                if (pid == 0) { // child
                    close(_listen_sockfd);

                    startService(sockfd);

                    close(sockfd);
                    exit(EXIT_SUCCESS);
                }
                close(sockfd);
                // int ret = waitpid(pid, nullptr, 0);
                // if (ret > 0) {
                //     logMessage(NORMAL, "wait child process success! %d", pid);
                // }

                // logMessage(DEBUG, "test");
                
            } //@end for(;;)

        } //@end void start()

    private:
        void startService(const int& sockfd) {
            while (true) {
                //task 读取一个完整的请求
                std::string request_package;
                if (!receivePackage(sockfd, &request_package)) {
                    logMessage(ERROR, "receive request_package fail!");
                    return;
                }
                logMessage(NORMAL, "receive request_package success! %s", request_package.c_str());

                //task 为读到的包文去掉报头
                std::string request_text(removeHeader(request_package));
                if (request_text == "") {
                    logMessage(ERROR, "remove request_package header fail!");
                    return;
                }
                logMessage(NORMAL, "remove request_package header success! %s", request_text.c_str());

                //task 为request反序列化
                Request request;
                if(!request.unserialize(request_text)) {
                    logMessage(ERROR, "request unserialize fail!");
                    return;
                }
                logMessage(NORMAL, "request unserialize success!");

                //task 调用service来处理从request中提取的数据(处理业务)，并把结果存进response中
                Response response;
                _service(request, response);

                //task 为response序列化
                std::string response_text;
                if (!response.serialize(&response_text)) {
                    logMessage(ERROR, "response serialize fail!");
                    return;
                }
                logMessage(NORMAL, "response serialize success! %s", response_text.c_str());

                //task 为response_text添加报头构成包文
                std::string response_package(addHeader(response_text));
                logMessage(NORMAL, "response_text addHeader success! %s", response_package.c_str());

                //task 向sockfd中发送包文
                send(sockfd, response_package.c_str(), response_package.size(), 0);

            } //@end while(true)

        } //@end void startService()

    }; //@end class TcpServer

} //@end namespace server